Perdixo Posted November 2, 2019 Share Posted November 2, 2019 Hey guys, I'm using Pixi.js to create a blog page template that uses a displacement texture to distort the post images (on load, on hover and reverse it on click). My issue is that i can't figure out how to affect the borders of my image, so when you hover it for example, the borders also move (now they are static). The image texture is displaced, but i'd like it to affect the containers borders. I know this might sound easy, but for some reason i can't figure out what i'm missing here... I've created a jsfiddle for live code. here is my html <div class="section"> <div class="section__image" data-index="1" data-src="https://source.unsplash.com/random/"> </div> <div class="section__content"> <h2>Lorem ipsum dolor.</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Debitis, rem. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium assumenda atque distinctio eos illo minima, mollitia officiis pariatur provident! Architecto cum facilis nostrum sit voluptate. Dignissimos dolores enim quidem totam?</p> </div> </div> <div class="section"> <div class="section__image" data-index="2" data-src="https://source.unsplash.com/random"> </div> <div class="section__content"> <h2>Lorem ipsum dolor.</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Debitis, rem. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto asperiores dicta eius, est eum itaque magnam officia perspiciatis porro sequi. Autem ea ipsa sed ullam.</p> </div> </div> <div class="section"> <div class="section__image" data-index="3" data-src="https://source.unsplash.com/random"> </div> <div class="section__content"> <h2>Lorem ipsum dolor.</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Debitis, rem. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad autem est incidunt iusto obcaecati provident quod sequi ut veritatis. At atque aut blanditiis consequatur distinctio dolor, et, ipsa iste nam numquam officia pariatur perferendis possimus provident quibusdam quod repellendus vitae!</p> </div> </div> <div class="section"> <div class="section__image" data-index="4" data-src="https://source.unsplash.com/random"> </div> <div class="section__content"> <h2>Lorem ipsum dolor.</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Debitis, rem. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur eius nemo perspiciatis quia sit temporibus.</p> </div> </div> Here is my css * { box-sizing: border-box; } html, body { height: 100%; } body { margin: 0; font-family: 'Helvetica', serif; } .section { display: flex; flex-direction: column; align-items: center; margin: 0 auto; padding: 50px 0; max-width: 960px; } .section__image { position: relative; overflow: hidden; flex-shrink: 0; width: 100%; height: 100%; } .section__image > img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } .section__content { padding: 10px 0 0; } And here is my javascript // Note : Resize logic to fit the textures with canvas => https://github.com/pixijs/pixi.js/wiki/v4-Tips,-Tricks,-and-Pitfalls#resizing-renderer class ImageLoader { constructor(element) { this.wrapper = element; this.width = element.getBoundingClientRect().width; this.height = element.getBoundingClientRect().height; this.src = element.dataset.src; this.mouseOn = false; this.animated = false; this.app = new PIXI.Application(this.width, this.height, {transparent: true}); this.wrapper.append(this.app.view); this.container = new PIXI.Container(); const parent = this.app.view.parentNode; this.app.renderer.resize(parent.clientWidth, parent.clientHeight); this.app.stage.addChild(this.container); this.load(this.startAnimation.bind(this)); } load(afterLoad) { let tmpImg = new Image(); tmpImg.src = this.src; tmpImg.addEventListener('load', () => { afterLoad(); }); } startAnimation() { const that = this; // create pixi image and add it to container this.bg = PIXI.Sprite.fromImage(this.src); //this.bg.width = this.app.screen.width; this.bg.width = this.width; // this.bg.height = this.height; this.bg.position.x = 0; this.bg.position.y = 0; this.container.addChild(this.bg); // create filter this.displacementSprite = PIXI.Sprite.fromImage('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123024/disp5.jpg'); this.displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT; // cover with filter all image this.displacementFilter = new PIXI.filters.DisplacementFilter(this.displacementSprite); // set filter scale this.displacementFilter.scale.set(1e4 + Math.random()*1000); this.displacementSprite.scale.set(0.4 + 0.6*Math.random()); // add filter to container & stage (for waves effect on hover) this.app.stage.addChild(this.displacementSprite); this.container.filters = [this.displacementFilter]; this.click(); // animate displacementFilter on image let tl = new TimelineMax({onComplete:function() {that.animated = true;}}); tl.to(that.displacementFilter.scale,1,{x:1,y:1}); this.hover(); } click() { let that = this; this.wrapper.addEventListener('click',() => { let tl = new TimelineMax( {onComplete:function() {that.animated = true;}} ); tl.to(that.displacementFilter.scale,1,{x:1,y:1}); }); } hover() { let that = this; this.wrapper.addEventListener('mouseenter',function() { if(!that.mouseOn && that.animated) { that.mouseOn = true; TweenMax.ticker.addEventListener('tick',that.doWaves, that); // same as requestAnimationFrame let tl = new TimelineMax(); tl.to(that.displacementFilter.scale,0.5,{x:20,y:10}); } }); this.wrapper.addEventListener('mouseleave',function() { if(that.mouseOn && that.animated) { that.mouseOn = false; TweenMax.ticker.removeEventListener('tick',that.doWaves, that); let tl = new TimelineMax(); tl.to(that.displacementFilter.scale,0.5,{x:1,y:1}); } }); } doWaves() { this.displacementSprite.x += 1; } } const imageNodeList = document.querySelectorAll( '.section__image'); Array.prototype.forEach.call(imageNodeList, function (node) { const img = new ImageLoader(node); }); Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted November 3, 2019 Share Posted November 3, 2019 make canvas bigger than the image, and use `containerfilterArea = app.screen` Also I hope you dont forget that there is a limit on webgl contexts number, and sometimes its very low. You have to re-use or destroy contexts that are out of the screen right now. Quote Link to comment Share on other sites More sharing options...
Perdixo Posted November 3, 2019 Author Share Posted November 3, 2019 Hey @ivan.popelyshev, Thanks for the answer! Sorry but i'm new to webgl and PIXI, so i might have some more questions.. I'm not sure to understand how to do this. For the canvas, i guess i might change its size in my constructor by changing this line this.app.renderer.resize(parent.clientWidth, parent.clientHeight); But i couldn't find how to use the `containerfilterArea = app.screen` .. For the last part i've read about it, i might have to create a plane that i'll reuse each time so only one animation car happer at a time right? Thanks for your time ? ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted November 3, 2019 Share Posted November 3, 2019 (edited) Oh, i missed the dot. "container.filterArea = app.screen" for that container you place your filter on. You need it to take borders that you creaet by using renderer bigger than the image. Or you can add padding to filter: "displacementFilter.padding = 20" , something like that. Yes, you have to create a plane and move it to be above image you want to show effects on. That's the price of using webgl. I know that DisplacementFilter is our selling point for people who want image effects on html page. Welcome to the forums! Edited November 3, 2019 by ivan.popelyshev Perdixo 1 Quote Link to comment Share on other sites More sharing options...
Perdixo Posted November 3, 2019 Author Share Posted November 3, 2019 (edited) Thanks @ivan.popelyshev So i've tried to apply this to my code but for some reason i can't figure out how to implement this. I've started by adding this line in my constructor this.container.filterArea = this.app.screen; Resizing the renderer doesn't work, but i think i don't do it the right way.. i've tried many things, as modyfing the line 16 with this.app.renderer.resize(parent.clientWidth + 100, parent.clientHeight + 100); but it scales the entire thing and its borders, so it only makes my image bigger with the same issue. And when using this.displacementFilter.padding = 100; i'm still having the same beginning issue. The only thing that worked for the borders is modifying the sprite width, but that messes up the layout.. this.bg.width = this.app.screen.width - 100; this.bg.height = this.app.screen.height - 100; I think i'm not changing the renderer size the right way? Thanks for the welcome and for your time! Edited November 3, 2019 by Perdixo Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted November 3, 2019 Share Posted November 3, 2019 (edited) but you didnt move the image itself. OK, basically, layout is your problem, pixi doesnt know what "layout" is. It knows position, scale, rotation. Changing width is actually changing scale. Its your job to modify position that way Sprite is at the center of the canvas. Please look through simple demos first: https://pixijs.io/examples/#/sprite/basic.js , https://pixijs.io/examples/#/demos-basic/container.js Tell me if you dont get it after that, we can wait for someone to have time to actually modify your demo the way it works Its probably 5 minutes, but i dont want to do all the job. In your case its probably just "container.position.set(50,50)" Edited November 3, 2019 by ivan.popelyshev Quote Link to comment Share on other sites More sharing options...
Perdixo Posted November 3, 2019 Author Share Posted November 3, 2019 @ivan.popelyshev Yess thanks, what i did is change the bg.width and set the container position. It works but the thing is that now the image is smaller than the original. I wonder if there's a better way to preserve the layout. If someone could check the code that would be awesome! Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted November 4, 2019 Share Posted November 4, 2019 (edited) On 11/4/2019 at 1:07 AM, Perdixo said: @ivan.popelyshev Yess thanks, what i did is change the bg.width and set the container position. It works but the thing is that now the image is smaller than the original. I wonder if there's a better way to preserve the layout. If someone could check the code that would be awesome! OK, then you are on the right way. Unfortunately, I'm still way too busy to look at it. I usually recommend people to check if they understand what is "canvas size" , "css size", "sprite size" and what is "transform". If I just change your code, you will have the same problems next time when you use any other 2d renderer. As an example, you wouldn't have that problem if you used Adobe Flash before: it has the same structure of tree. Edited November 4, 2019 by ivan.popelyshev Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted November 4, 2019 Share Posted November 4, 2019 Basically, if you put canvas instead of image - it cant affect page that is out. I know its possible to make text inside DIV appear outside - but in this case you cant just command rogue pixels to go out of canvas I see that you use "image { width:100% } " in CSS, that means you have outer container - and iof course if you try to add border in the pixi stage, without resizing canvas/renderer if will squeeze the image. Its not even automatical - you do it by assigning "bg.width = width - 100". Suppose "WxH" is your original image size, try to make canvas of size (W+100) x (H+100) and make sure that CSS size is also bigger. If one is in percents, second is in pixels - well, that's a problem, in that case you have to take pen and paper, write it all down and try to solve it like a math equation, it usually helps me. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.