Jump to content

Make image cover sprite without distorting


Johnny Kontrolleti
 Share

Recommended Posts

That's how I currently load an image as a sprite. As for now, some image are distorted due to a different ration than the sprite's:

this.sprite = PIXI.Sprite.from(this.image);

this.dimensions = {
    width: window.innerWidth * 1.05,
    height: window.innerHeight * 1.05,
    alpha: 0
};

// later in code

getPosition = () => {
    if (!active) {
        this.sprite.position.set(window.innerWidth / 2, window.innerHeight / 2);
        this.sprite.width = this.dimensions.width;
        this.sprite.height = this.dimensions.height;
        this.sprite.anchor.set(0.5);
        this.sprite.alpha = this.dimensions.alpha;
    } else {
        const {width, height, top, left} = document.querySelector('.detail__image').getBoundingClientRect();
        this.sprite.position.set(left, top);
        this.sprite.width = width;
        this.sprite.height = height;
        this.sprite.anchor.set(0);
        this.sprite.alpha = this.dimensions.alpha;
    }
};

update = () => {
    if (!this.sprite) return;
    this.getPosition();
}

As you can see, when active is true, the sprite is bound to a html element, if not it's about the size of the window.

How can I make the image cover the sprite, without distorting? Just like `background-size: cover` or `object-fit: cover`.

Tried to find something online, but couldn't make it work for me.

Link to comment
Share on other sites

12 hours ago, ivan.popelyshev said:

It shouldn't be distorted. Please make a whole demo and we can help you fix it. ZIP-file or any existing sandbox services are ok.

Here's a quick pen: https://codepen.io/magiix/pen/ZEbaKQg?editors=0010

That's how it usually should look like: Image - I want the image to adjust it's size just like `background-size: cover` etc. - it this possible? 

Thanks for your help again!!!

Link to comment
Share on other sites

Oh, that! That's one of basic exercises with transforms, solves with javascript functions "Math.min" and "Math.max", or pair of IF's. 

sprite.position.set(app.screen.width/2, app.screen.height/2 ); //same as your innerWidth
sprite.anchor.set(0.5);
sprite.scale.set(Math.min(app.screen.width / sprite.texture.width, app.screen.height / sprite.texture.height);

PixiJS does not have its own alignment/reflow system. Dfiferent people write it different way => we supply only basic transforms.

Link to comment
Share on other sites

On 5/3/2020 at 2:01 PM, ivan.popelyshev said:

Oh, that! That's one of basic exercises with transforms, solves with javascript functions "Math.min" and "Math.max", or pair of IF's. 

sprite.position.set(app.screen.width/2, app.screen.height/2 ); //same as your innerWidth
sprite.anchor.set(0.5);
sprite.scale.set(Math.min(app.screen.width / sprite.texture.width, app.screen.height / sprite.texture.height);

PixiJS does not have its own alignment/reflow system. Dfiferent people write it different way => we supply only basic transforms.

I have another case this unfortunately is not working, because this time the window isn't the container, but a small html element it's supposed to follow on scroll. 

So if I use the following, the images are not distorted and perfectly scaled to the container's size, but overflowing:

const {width, height, top, left} = this.$els.image.getBoundingClientRect();
this.sprite.position.set(left + width / 2, top + height / 2);
this.sprite.scale.set(Math.max(width / this.sprite.texture.width, height / this.sprite.texture.height));
this.sprite.anchor.set(0.5)

 

Using this makes the image not overflow, but distort again, since it's stuffed into this little container again:

const {width, height, top, left} = this.$els.image.getBoundingClientRect();
this.sprite.position.set(left + width / 2, top + height / 2);
this.sprite.scale.set(Math.max(width / this.sprite.texture.width, height / this.sprite.texture.height));
this.sprite.anchor.set(0.5)
this.sprite.width = width;
this.sprite.height = height;

 

Edited by Johnny Kontrolleti
Link to comment
Share on other sites

I added an AlphaFilter, which is kind of working - but how do I update it's position? Do I need to redraw the filterArea on update?

getMask = () => {
    const {width, height, top, left} = this.$els.image.getBoundingClientRect();
    this.sprite.filters = [new PIXI.filters.AlphaFilter()];
    this.sprite.filterArea = new PIXI.Rectangle(left, top, left + width, top + width);
};

 

Link to comment
Share on other sites

53 minutes ago, ivan.popelyshev said:

there shouldn't be a problem in case sprite doesnt get out of screen. The problem exists because filter scales everything down -> it needs some info "from beyond the screen" . You should use Sprite bounds and not getBounding stuff if you need it

Thanks the efforts again, but I smh still can't make it run.

The sprite is overflowing a normal html container, as you can see in the image below. - All images should be of same width, but some images, probably a different ratio do overflow.

const {width, height, top, left} = this.$els.image.getBoundingClientRect();
this.sprite.position.set(left + width / 2, top + height / 2);
this.sprite.scale.set(Math.max(width / this.sprite.texture.width, height / this.sprite.texture.height));
this.sprite.anchor.set(0.5);

Setting width and height will restrict the sprite's area to my elements width and height, but cramp/distort the images. I need a way to cut/hide that overflow.

Bildschirmfoto_2020-05-04_um_22_09_43.png

Edited by Johnny Kontrolleti
Link to comment
Share on other sites

oh, you want to use filterArea to clamp sprites! tehre are two more ways:

1. add rect graphics inside sprite that is also its mask, coords local. (anchor=0.5, then 0,0 in graphics is sprite center)

2. modify texture frame. "const frame = sprite.texture.frame; frame.x = ... frame.y = ..." where x,y,width,height is culled the way you want, use JS min/max and positioning here, im sure you can do the math. Dont forget to call "texture.updateUvs()" afterwards. If you have one texture on multiple sprites, i recommend to clone texture before you assign it to sprite (works in >5.2.2)

1 is faster than filter, 2 is significantly faster. But if you need alphaFilter anyway, you can use your trick with filterArea, yep :)

Edited by ivan.popelyshev
Link to comment
Share on other sites

22 hours ago, ivan.popelyshev said:

oh, you want to use filterArea to clamp sprites! tehre are two more ways:

1. add rect graphics inside sprite that is also its mask, coords local. (anchor=0.5, then 0,0 in graphics is sprite center)

I tried the following, but somehow the sprite completely disappeared - well at least this shows that the mask is working ?

const {width, height, top, left} = this.$els.image.getBoundingClientRect();
this.sprite.position.set(left + width / 2, top + height / 2);
this.sprite.scale.set(Math.max(width / this.sprite.texture.width, height / this.sprite.texture.height));
this.sprite.anchor.set(0.5);

const mask = new PIXI.Graphics();
mask.drawRect(0,0, this.sprite.width, this.sprite.height);
this.sprite.mask = mask;

 

Edited by Johnny Kontrolleti
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...