pixi-viewport icon indicating copy to clipboard operation
pixi-viewport copied to clipboard

Viewport and Rotation

Open adam-savard opened this issue 3 years ago • 8 comments

I've got something I'm a little stumped by.

I'm working on a large project where we use Viewport; viewport.center, when a stage is not rotated, works just fine and how we would expect. Global coordinates in a 1:1 fashion to our world stage.

When we rotate the world stage, however, some strangeness happens. "Navigating" the stage works just fine, as you would expect. The center doesn't seem to account for rotation, though.

Let's say I rotate my world stage 90 degrees (or the equivalent in radians since it's Pixi) counter-clockwise using viewport.center as the pivot. I then pan up the stage for n length. When I want to rotate again, using viewport.center, n length is not translated into negative-y, but instead negative-x, teleporting the world stage to that point.

Is this intended behavior? I just want to make sure there isn't something I haven't thought of.

adam-savard avatar Jan 06 '21 19:01 adam-savard

I'm afraid that's the current behavior. I've not added rotation support to the viewport. There are some calculations that will likely be broken when using a rotated viewport (although rotated elements within the container should work fine.

This is on my love-to-do list along with supporting two-finger rotation, but I haven't had any need for it in my projects. I'm happy to accept a PR if you're interested in taking a crack at it.

davidfig avatar Jan 06 '21 23:01 davidfig

@davidfig Is this the same feature that would be needed for a viewport.follow that can follow also the rotation of the target and not just its position?

Unfortunately the lack of this feature is project breaking for me, but I realized I needed it only halfway through, so now I'm stuck with weeks of work that I can't finish.

How hard would this be to implement?

pietrovismara avatar Jan 26 '21 17:01 pietrovismara

If you mean rotating the entire viewport to match the target's rotation, then, yes, this is not available.

The actual rotation of the viewport itself shouldn't be too difficult. The difficult part is to backport the plugins (like pinch and drag) to ensure they work with the rotated viewport. Until someone digs in, I don't know how much work that entails.

davidfig avatar Jan 26 '21 22:01 davidfig

So I tried to tackle this for a few hours yesterday. I am not as worried about the pivot for the animation during the angle change, but moreso the actual interaction when the angle is fully set. As of right now, when I shift the angle of the viewport, the worldHeight and and worldWidth stay on the calculated left and top of the app screen to the width and height of the app screen, making it impossible to use viewport at certain quadrants. When I change the forceHitArea to include a larger area by default, I get a really weird behavior that stems at how visible is being calculated. Panning the viewport works fine, but on wheel, in only certain patches of the viewport the event is prevented all together.

I've done a bit of debugging, and I was able to figure out that the reason that it was failing is because the 3rd parent of the viewport in the location of where I was scrolling has the property visible set to false. This escapes me because I have no idea what the third parent is (Application (Container?) => Stage (Container) => Viewport (Container) and because I have no idea why it is set to not visible and only in certain small patches of the viewport despite me seeing the entire viewport.

I'll do a bit more debugging, but I don't want to do extra work if this has already been solved or if I'm doing something wrong.

To add clarification, I am setting angle on the viewport itself. When I tried adding a container the panning got messed up.

slyduda avatar Sep 15 '21 16:09 slyduda

Hmm...that is weird. PIXI.Application includes a default stage, but there shouldn't be any parent above that. I'm not sure how visible would be set to false as I don't think pixi-viewport touches that. I can take a look at some code if you have a version that's up and running and see if I can help debug.

davidfig avatar Sep 15 '21 16:09 davidfig

Sure!

Before I paste a snippet of my code, I've done a bit more digging and I noticed that I get different results from the way that these two event listeners are set. On mouse down in the viewport, this.viewport.worldVisible will return true at any location if the forceHitArea is set manually, but on the wheel event this.viewport.worldVisible returns false in the upper right and lower left quadrants (I think? as opposed to me saying it happened in random areas in an earlier comment) EDIT: I think it just has to do with the viewport location and the application sizing.

Here is the snippet of the source code that creates the difference between both event listeners.

    this.viewport.on('pointerdown', this.up, this);
    this.wheelFunction = (e) => this.handleWheel(e);
    this.viewport.options.divWheel.addEventListener(
        'wheel',
        this.wheelFunction );

A simplified versionof my code looks like this:

const application = new PIXI.Application({
        view: canvas,
        backgroundColor: 0xf2f2f2,
        antialias: true
      })
      application.stage.interactive = true

    const viewport = new Viewport({
        worldHeight: 1000000,
        worldWidth: 1000000,
        forceHitArea: new PIXI.Rectangle(-500000, -500000, 1000000, 1000000),
        interaction: application.renderer.plugins.interaction // the interaction module is important for wheel to work properly when renderer.view is placed or scaled
    })
    .clampZoom({ minWidth: 500, minHeight: 500, maxWidth: 5000, maxHeight: 5000 })

    // activate plugins
    viewport
    .drag({mouseButtons: 'left-middle'})
    .pinch()
    .wheel()
    .decelerate()

    viewport.angle = 90

  application.stage.addChild(viewport)

I am currently using "pixi-viewport": "^4.32.0" for my version.

slyduda avatar Sep 15 '21 18:09 slyduda

Hmm...that is weird. PIXI.Application includes a default stage, but there shouldn't be any parent above that. I'm not sure how visible would be set to false as I don't think pixi-viewport touches that. I can take a look at some code if you have a version that's up and running and see if I can help debug.

Just to clarify on this comment, the viewport interactions check if this.worldVisible on one of the first checks. If it is false then it returns before the interaction occurs and the event logic happens. I only noticed this for the broken spaces (where the viewport wheel fails, but drag doesn't). This check fails only for the wheel event and not for drag or technically pointer down. When I dug further into it, I found that worldVisible is set by visible.

Unfortunately, when I removed this check though, the interaction still failed to occur, so maybe I'm just not on the right track at all, but the example that I gave should demonstrate that wheel is not activating where drag does when the viewport is rotated.

slyduda avatar Sep 16 '21 17:09 slyduda

I made a fiddle to hopefully help clarify what I was saying! I've spent some time in the source, but I'm still a little stumped as this is a little above my knowledge pool, but I'd still love to help solve it! https://jsfiddle.net/slyduda/73k4aozt/71/

The fiddle should demonstrate the following:

  • Viewport pan and zoom work perfectly fine at the start of the app within the respective bounds set by the force hit area
  • Viewport pan works perfectly fine after the viewport is rotated (after clicking the button), but the zoom fails at certain locations (most likely due to the left, top and app height and width calculations)

EDIT: I'm noticing some issues with zooming even at angle 0 in the fiddle, though this does not occur in my actual app. Not sure what the discrepancy is. I think it may have to do with the jsfiddle height and width as it only occurs when zooming on the right half of the screen.

EDIT 2: Noticing that the issue is not very visible when scrolling out far. I didn't notice this before because I clamped my zoom, but you should notice zoom noticably break at the default zoom scaling.

slyduda avatar Sep 20 '21 18:09 slyduda