Pixi.js: Give an option to set fixed bounds on a container

Created on 23 Sep 2016  ·  15Comments  ·  Source: pixijs/pixi.js

I am running into a problem where I draw something inside a container and that container's bounds get immediately recalculated. While that particular example is of course rather contrived - in reality I'd draw something like this only once, I can see a lot of potential issues coming from this behaviour (e.g. let's say I put some off-screen item into the container that the user can swipe-in from the side, that would completely destroy the snapping logic I have there right now).

💾 v4.x (Legacy) 🤔 Question

Most helpful comment

Hey @megakoresh, I think I know what is causing the confusion here. Since pixi's main purpose is to render 2D objects, almost all of the API is geared towards that end. Bounds can be particularly confusing.

In pixi, a Sprite's bounds are defined by the texture. That is, the size of the end-result of the rendered object. Similarly, since a Container is _not drawn_, and therefore the bounds of it are defined by the children it contains. Particularly, by the bounds of those children. For a Graphics object, the bounds are defined by the geometry that you draw in it. If you draw another rectangle in a Graphics object outside of the current bounds, the bounds expand to include the newly drawn geometry.

Hopefully that makes sense, and gives you a quick concept of how bounds are structured in Pixi.

Now, specifically for your example, I believe your issue is coming from the misunderstanding of how bounds work for a Graphics object. I think you are missing that drawing your grid is changing the bounds of the Graphics object (desktop1) that contains the green rect (wonderfulRectangle).

You can see that after the first draw, your grid extends off the size of the viewport:

image

This extends the bounds of the parent Graphics object (desktop1) to include the out-of-viewport geometry. This makes your width larger, which throws off your next calculation of the grid, and the cycle continues. Remember, the lines have thickness and therefore take up width.

There are a couple ways to fix this, the one that comes to mind is that since your grid fills the entire size of the viewport, just use the size of the viewport rather than the size of your parent. This means if/when you draw more geometry outside of the viewport, your grid calculations never change. Because the rendering viewport doesn't change size.

If that isn't an option, for example your grid area is not the size of the viewport. You can just do the calculations based on a "known size" of the grid area. I think that was what Ivan was trying to say about using a static Rectangle instance. Basically, decide that your grid is 800x600 and do calculations based off of that rather ran the actual rendered bounds of objects in the scene.

I've updated the codepen to use the viewport method I described. Let me know if you have any further questions!

http://codepen.io/anon/pen/yarVwm?editors=0010

All 15 comments

Container doesnt have area and fixed bounds, it is just a collection of children, and that's default PIXI behaviour. If you want to fix the bounds, extend your own container, override "calculateBounds" method.

If it doesn't have an area and fixed bounds and is essentially just a data structure then it shouldn't affect rendering (similar to how if you put an object that's too large into an iframe, the iframe is not going to get bigger). In the example it clearly does, and I find it difficult to blame that on faulty logic of the example. Maybe not having a fixed bounds option is not looking at the root of the problem, but the problem is definitely there.

How would you suggest I implement "off-screen" elements?

Why do you need bounds anyway?

Have you looked at the example? The weird behaviour is caused by the fact that every time drawDebugLines gets executed and draws the lines in the "icon's" container, that container gets bigger. Which in turn messes up the snap points, as those are dependent on the container dimensions (width/columns, height/rows).

If I map the snapping to the rendering element that introduces 2 problems: the renderer depends on the screen size, orientation, pixel density and the user-specified dimensions of the drawing element. It can contain items that are both bigger than it (e.g. off-screen, that can slide in) and smaller (e.g. if I make desktop 1 and desktop2 visible at the same time. In all those cases the snapping and other constrains must be preserved.

lel.width = wonderfulRectangle.width * 0.8;
lel.height = wonderfulRectangle.height * 0.9;

why dont you use it as a constant? Can you just setup something global, like that:

var globalRect = new PIXI.Rectangle(0, 0, renderr.width/renderer.resolution, renderer.height/renderer.resolution);

update that rect on every resize, and work with that. Why do you need "lel.width" and "lel.height"?

LEL. That one has nothing to do with anything, it's just a Sprite that can be moved around and I am setting the width and height because the original image is too big and I need to fit it into a rectangle. If you look the code in the , you'll see the main container for that "icon" is desktop1 and it's that to which I am trying to snap the icon to. That one belongs to the desktopLayer and the desktopLayer is the one I put on the stage.

What I am trying to emulate is the behaviour of an Android Launcher screen with multiple swipable views and an icon grid over a desktop background.

return new PIXI.Point(snapPosX.clamp(0, target.parent.width), snapPosY.clamp(0, target.parent.height));

I still dont understand what do you want. PIXI container bounds work exactly like they are supposed to. You are not the first who made this mistake.

Oh maker's breath, I can't do this anymore. Can anyone just look at the example, move the rageface around and tell me why that crap with the lines is happening and whether it's a bug/missing feature in PIXI or if I have a mistake in the code?

I thought that's because your lines actually affecting container width and height and you use those properties to draw lines in the first place.

Also codepen isnt working for me anymore, somehow. Any ideas why?

Yeah its broken for me also because I accidentally commented out the init call, my bad, sorry, fixed. Yes you are correct - that is what I do and I don't see any other way for me to draw those lines to reflect the grid visually. So what exactly would you propose for me to draw these lines? Set up some kind of separate meta-only Rectangle object that always copies dimensions of the it's associated rendered container and use that to derive the snapping points and other positions? That seems like over-engineering around the problem instead of solving it. Is there any reason why a container can not have "overflow" like a normal DOM element?

I posted this as an issue not because there's no solution but because I can't see justification for this illogical behaviour. Especially because the lines do not actually go outside the container bounds, they are drawn from edge to edge. In the product I am building the user is expected to do a lot of interaction with the content, I am worried that if I have to set up "reference rectangles" for every object in the scene the code will be extremely messy and hard to maintain.

You mentioned I had a "mistake" in my code. What is that mistake? I searched very thoroughly but can't find any faulty logic.

Use some global variable instead of "width/height" that are changing. Update that variable when needed.

var globalRect = new PIXI.Rectangle(0, 0, renderer.width/renderer.resolution, renderer.height/renderer.resolution);

If you want "local" bounds, then make them, but dont use the same variables as pixi:

container.myRect = new PIXI.Rectangle(0, 0, renderer.width/renderer.resolution, renderer.height/renderer.resolution);

The mistake is that there's no layout in PIXI, at all. "width" and "height" have different meaning. You cant clamp child coords by parent width height, because child affects them.

There's no way for PIXI to know that you want width/height of some rectangle you drawn inside graphics, and not whole graphics bounds (what if there are circles too?), and not child bounds. The only reasonable logic for bounds is to take everything inside in them.

Imagine that we have container with two sprites, each has (w=10, h=10), one is in (0,0) second one is in (100000, 100000). What width and height that container has? Also, even if we somehow fix bounds, what will they affect?

And what if we want to change width and height somehow, how will that change affect elements inside container?

I'm not joking, its really difficult for me to imagine other designs of API. If you have some ideas, may be additional component for layout, please write it here. Just remember that we are dealing with stage rendering and not some GUI, performance is real problem.

Hey @megakoresh, I think I know what is causing the confusion here. Since pixi's main purpose is to render 2D objects, almost all of the API is geared towards that end. Bounds can be particularly confusing.

In pixi, a Sprite's bounds are defined by the texture. That is, the size of the end-result of the rendered object. Similarly, since a Container is _not drawn_, and therefore the bounds of it are defined by the children it contains. Particularly, by the bounds of those children. For a Graphics object, the bounds are defined by the geometry that you draw in it. If you draw another rectangle in a Graphics object outside of the current bounds, the bounds expand to include the newly drawn geometry.

Hopefully that makes sense, and gives you a quick concept of how bounds are structured in Pixi.

Now, specifically for your example, I believe your issue is coming from the misunderstanding of how bounds work for a Graphics object. I think you are missing that drawing your grid is changing the bounds of the Graphics object (desktop1) that contains the green rect (wonderfulRectangle).

You can see that after the first draw, your grid extends off the size of the viewport:

image

This extends the bounds of the parent Graphics object (desktop1) to include the out-of-viewport geometry. This makes your width larger, which throws off your next calculation of the grid, and the cycle continues. Remember, the lines have thickness and therefore take up width.

There are a couple ways to fix this, the one that comes to mind is that since your grid fills the entire size of the viewport, just use the size of the viewport rather than the size of your parent. This means if/when you draw more geometry outside of the viewport, your grid calculations never change. Because the rendering viewport doesn't change size.

If that isn't an option, for example your grid area is not the size of the viewport. You can just do the calculations based on a "known size" of the grid area. I think that was what Ivan was trying to say about using a static Rectangle instance. Basically, decide that your grid is 800x600 and do calculations based off of that rather ran the actual rendered bounds of objects in the scene.

I've updated the codepen to use the viewport method I described. Let me know if you have any further questions!

http://codepen.io/anon/pen/yarVwm?editors=0010

LOL k. So with your combined efforts I think I understand the core of the issue: I think I was thinking that if the library is often put together with canvas libraries, that I assumed it is the same thing, which it clearly isn't. I guess then taking care of visual object grouping and things like overflow are simple not in scope (maybe when I learn the library more I can make a plugin for that) and I need to take care of those things myself, while PIXI itself takes care of just displaying things on the screen. Case closed, thanks.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Vardner picture Vardner  ·  3Comments

YuryKuvetski picture YuryKuvetski  ·  3Comments

lucap86 picture lucap86  ·  3Comments

finscn picture finscn  ·  3Comments

Cristy94 picture Cristy94  ·  4Comments