Agent Zebra
Agent Zebra

Reputation: 4550

Dynamically resize the pixi stage and it's contents on window resize and window load

I'm trying to dynamically resize the pixi stage (canvas and contents) on window resize. And also have it initially load at the size of the browser window without changing ratio.

I'm using the following to set the initial size basically to window.innerWidth & window.innerHeight.

But it's doing something strange, it's loading at a smaller size (but not the size of the canvas specified in the html) then it's expanding to fit the window.

var w;
var h;
    
window.onload = function() {
    var w = window.innerWidth;
    var h = window.innerHeight;

    //this part resizes the canvas but keeps ratio the same
    renderer.view.style.width = w + "px";
    renderer.view.style.height = h + "px"

//  init();
}; 

Here's my onresize function - it's resizing the canvas, but not the content.

I thought being that it's updating the renderer.view, it would resize the content, but it's not doing so.

How do I resize the content of the stage/renderer.view content?

window.onresize = function (event){
    var w = window.innerWidth;
    var h = window.innerHeight;

    //this part resizes the canvas but keeps ratio the same
    renderer.view.style.width = w + "px";
    renderer.view.style.height = h + "px";

    //this part adjusts the ratio:
    renderer.resize(w,h);
}

    // create an new instance of a pixi stage
    var stage = new PIXI.Stage(0xff00ff);
    var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight);

    // add the renderer view element to the DOM
   var mypixiStage = document.body.appendChild(renderer.view);

Upvotes: 31

Views: 68558

Answers (7)

Motla
Motla

Reputation: 1230

Starting from PixiJS 5.0 you can simply use the resizeTo property of your Application:

let app = new PIXI.Application({ resizeTo: window });

Documentation: https://pixijs.download/release/docs/app.Application.html#resizeTo

Upvotes: 53

user22362523
user22362523

Reputation: 1

A CSS solution would be more viable and better choice for resizing the canvas rather than updating it from window "resize" events that the others have answered, since you do not need to change the contents' positions and could give better performance.

You can add a canvas element with an id of your choice in your HTML file and assign it to the view property of your application.

<canvas id="game"></canvas>
const app = new PIXI.Application({
    width: 960,
    height: 540,

    view: document.getElementById("game")
});

Then, add this into your CSS file:

#game {
    padding: 0;
    margin: 0;

    width: 100vw; 
    max-width: 100%; /* ensures that it doesn't overflow */
    height: auto;
    max-height: 100%; /* ensures that it doesn't overflow */

    user-select: none; /* removes accidental selection */
}

Adjust the CSS properties to however it fits your website.

Upvotes: 0

Benedict Kpaduwa
Benedict Kpaduwa

Reputation: 1

var mobiledev;
if (window.innerWidth <= window.innerHeight){
   mobiledev = true;
   app.renderer.resize(window.innerWidth, window.innerHeight + (((((window.innerWidth * 100) / window.innerHeight) / 100) - 0.5) * window.innerWidth));
    } else {
   mobiledev = false;
   app.renderer.resize(window.innerWidth, window.innerHeight - (((((window.innerHeight * 100) / window.innerWidth) / 100) - 0.65) * window.innerWidth));
    }

I have been using PIXI.js for like close to a year and encountered problem when it came to resizing and responsiveness. This is a block of code I came up with and haven't had issues with responsiveness. I created an if statement to check for the device resolution and place the items according to it

Upvotes: 0

phip
phip

Reputation: 607

For my use case, I only need to scale a sprite based on its width. I do this using the scale function and clamping it to a max value of 1:

sprite.scale.set(Math.min(app.screen.width / sprite.texture.width, 1))

Starting with PixiJS 5.3.0 there's an resize event emitted on the renderer. This is thanks to issue #6081 opened by Fabian von Ellerts that he mentioned in his comment.

app.renderer.on('resize', (width, height) => {
  sprite.scale.set(Math.min(width / sprite.texture.width, 1))
})

⚠️ This will only set the dimensions of the sprite. You'll still need to position it on the canvas in a similar manner, i.e also scale its position.

Upvotes: 2

Wagner Paz
Wagner Paz

Reputation: 181

app.renderer.resize(window.innerWidth, window.innerHeight);
window.onresize = function()
{
    app.renderer.resize(window.innerWidth, window.innerHeight);
}

Upvotes: 1

bullzito
bullzito

Reputation: 357

I been using Pixi.js for a few weeks and worked on the same problem of resizing the canvas. This class creates a sprite that has a method "applyResize" that does most of the work. The size of the canvas background will equal the same as the parent "domElement" in the constructor. You have to add 'resize' event listener to the sprite after initializing it. Or you can do something else to improve it.

class PixiBackground {

    constructor(type = 'cover', domElement, imgUrl) {
        this.domElement = domElement;
        this.imgUrl = imgUrl;
        this.parent = new PIXI.Container();
        this.sprite = new PIXI.Sprite.fromImage(this.imgUrl);
        this.parent.addChild(this.sprite);
        this.type = type;
    }

    addTo(container) {
        container.addChild(this.parent);
        this.applyResize();
    }

    applyResize() {
        const domSize = {
            x: this.domElement.clientWidth,
            y: this.domElement.clientHeight
        };
        const imageSize = {
            x: this.sprite.texture.width,
            y: this.sprite.texture.height
        };
        const domElementRatio = domSize.x / domSize.y;
        const imageRatio = imageSize.x / imageSize.y;
        var scale = 1;
        var position = new PIXI.Point(0, 0);

        if (this.type == 'cover' ? domElementRatio > imageRatio : domElementRatio < imageRatio) {
            //photo is taller than background
            scale = domSize.x / imageSize.x;
            position.y = -(imageSize.y * scale - domSize.y) / 2;
            position.x = 0;
        } else {
            //photo is wider than background
            scale = domSize.y / imageSize.y;
            position.x = -(imageSize.x * scale - domSize.x) / 2;
            position.y = 0;
        }
        this.sprite.scale = new PIXI.Point(scale, scale);
        this.sprite.position = position;
        return this;
    }
}

const imgUrl = 'https://images.unsplash.com/photo-1528723624453-3e53a413b392?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ&s=b44ae61a30e1a05f5defbf48cb5956eb';
const canvasParentElement = document.getElementById('canvasParentElement');
const renderer = PIXI.autoDetectRenderer({
    width: canvasParentElement.clientWidth,
    height: canvasParentElement.clientHeight
});
canvasParentElement.appendChild(renderer.view);

const stage = new PIXI.Container();
const pixiTestObject = new PixiBackground('cover', canvasParentElement, imgUrl);

PIXI.loader.add(imgUrl).load(function() {
    pixiTestObject.addTo(stage)
    requestAnimationFrame(animate);

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(stage);
    }
});

window.addEventListener('resize', debounce(() => onResizeWindow(), 250));
window.addEventListener('resize', debounce(() => pixiTestObject.applyResize(), 250));

// From underscrore.js
function debounce(func, wait, immediate) {
    let timeout;
    return function() {
        let args = arguments;
        let later = () => {
            timeout = null;
            if (!immediate) func.apply(this, args);
        };
        let callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(this, args);
    }
}

function onResizeWindow() {
    const canvas = renderer.view;
    const w = canvasParentElement.clientWidth;
    const h = canvasParentElement.clientHeight;
    canvas.style.width = w + 'px';
    canvas.style.height = h + 'px';
    canvas.width = w;
    canvas.height = h;
    renderer.resize(w, h);
}
  #canvasParentElement {
    background: black;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.1/pixi.min.js"></script>
<div id="canvasParentElement"></div>

Upvotes: 4

Bitwise Creative
Bitwise Creative

Reputation: 4105

You will want to setup a size and ratio for the resize event function to reference. Then, you'll need a resize function that checks the window size in order to keep the ratio when resized. I'm also running the resize function manually to start for initial page load.

Also, note that I'm not running renderer.resize. I'm just resizing the drawing area.

Here's a fiddle for you to look at: http://jsfiddle.net/2wjw043f/

Here's the fiddle code:

var size = [1920, 1080];
var ratio = size[0] / size[1];
var stage = new PIXI.Stage(0x333333, true);
var renderer = PIXI.autoDetectRenderer(size[0], size[1], null);
document.body.appendChild(renderer.view);
var texture = new PIXI.RenderTexture();
r1 = new PIXI.Graphics();
r1.beginFill(0x00ffff);
r1.drawRect(0, 0, 100, 100);
r1.endFill();
texture.render(r1);
var block = new PIXI.Sprite(texture);
block.position.x = 100;
block.position.y = 100;
block.anchor.x = .5;
block.anchor.y = .5;
stage.addChild(block);
requestAnimFrame(animate);
resize();
function animate() {
    requestAnimFrame(animate);
    block.rotation += .01;
    renderer.render(stage);
}
function resize() {
    if (window.innerWidth / window.innerHeight >= ratio) {
        var w = window.innerHeight * ratio;
        var h = window.innerHeight;
    } else {
        var w = window.innerWidth;
        var h = window.innerWidth / ratio;
    }
    renderer.view.style.width = w + 'px';
    renderer.view.style.height = h + 'px';
}
window.onresize = resize;

Upvotes: 33

Related Questions