Jump to content
Search Community

SVG Filter — Image Distortion Effect Problem

Guest
Moderator Tag

Recommended Posts

Hello everyone,

 

Hopefully this question is relevant in the GreenSock forum. I am working on implementing the SVG Filter effect on the third demo here. Everything works fine until you insert a div on top of the container including the SVG interaction. The div on top offsets where images appear and pushes them below. The offset amount is the same as the upper div's height. Does anyone know how this might be fixed?

 

Here is the script:

 

{
    const body = document.body;
    const docEl = document.documentElement;

    const lineEq = (y2, y1, x2, x1, currentVal) => {
        // y = mx + b 
        var m = (y2 - y1) / (x2 - x1), b = y1 - m * x1;
        return m * currentVal + b;
    };

    const lerp = (a,b,n) => (1 - n) * a + n * b;

    const distance = (x1,x2,y1,y2) => {
        var a = x1 - x2;
        var b = y1 - y2;
        return Math.hypot(a,b);
    };

    const getMousePos = (e) => {
        let posx = 0;
        let posy = 0;
        if (!e) e = window.event;
        if (e.pageX || e.pageY) {
            posx = e.pageX;
            posy = e.pageY;
        }
        else if (e.clientX || e.clientY)    {
            posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        }
        return { x : posx, y : posy }
    }

    let winsize;
    const calcWinsize = () => winsize = {width: window.innerWidth, height: window.innerHeight};
    calcWinsize();
    window.addEventListener('resize', calcWinsize);

    const feDisplacementMapEl = document.querySelector('feDisplacementMap');

    class Menu {
        constructor() {
            this.DOM = {
                svg: document.querySelector('svg.distort'),
                menu: document.querySelector('blockquote.quote')
            };
            this.DOM.imgs = [...this.DOM.svg.querySelectorAll('g > image')];
            this.DOM.menuLinks = [...this.DOM.menu.querySelectorAll('.quote__link')];
            this.mousePos = {x: winsize.width/2, y: winsize.height/2};
            this.lastMousePos = {
                translation: {x: winsize.width/2, y: winsize.height/2},
                displacement: {x: 0, y: 0}
            };
            this.dmScale = 0;

            this.current = -1;

            this.initEvents();
            requestAnimationFrame(() => this.render());
        }
        initEvents() {
            window.addEventListener('mousemove', ev => this.mousePos = getMousePos(ev));

            this.DOM.menuLinks.forEach((item, pos) => {
                charming(item);
                const letters = [...item.querySelectorAll('span')];

                const mouseenterFn = () => {
                    this.current = pos;
                    TweenMax.to(this.DOM.imgs[this.current], 0.5, {
                        ease: Quad.easeOut, 
                        opacity: 1
                    });

                    TweenMax.staggerTo(letters, 0.2, {
                        ease: Sine.easeInOut,
                        y: this.lastMousePos.translation.x < this.mousePos.x ? 30 : -30,
                        startAt: {opacity: 1, y: 0},
                        opacity: 0,
                        yoyo: true,
                        yoyoEase: Expo.easeOut,
                        repeat: 1,
                        stagger: {
                            grid: [1,letters.length-1],
                            from: this.lastMousePos.translation.x < this.mousePos.x ? 'start' : 'end',
                            amount: 0.12
                        }
                    });
                };
                const mouseleaveFn = () => {
                    TweenMax.to(this.DOM.imgs[this.current], 0.5, {ease: Quad.easeOut, opacity: 0});
                };
                item.addEventListener('mouseenter', mouseenterFn);
                item.addEventListener('mouseleave', mouseleaveFn);
            });
        }
        render() {
            this.lastMousePos.translation.x = lerp(this.lastMousePos.translation.x, this.mousePos.x, 0.15);
            this.lastMousePos.translation.y = lerp(this.lastMousePos.translation.y, this.mousePos.y, 0.15);
            this.DOM.svg.style.transform = `translateX(${(this.lastMousePos.translation.x-winsize.width/2)}px) translateY(${this.lastMousePos.translation.y-winsize.height/2}px)`;

            // Scale goes from 0 to 50 for mouseDistance values between 0 to 100
            this.lastMousePos.displacement.x = lerp(this.lastMousePos.displacement.x, this.mousePos.x, 0.07);
            this.lastMousePos.displacement.y = lerp(this.lastMousePos.displacement.y, this.mousePos.y, 0.07);
            const mouseDistance = distance(this.lastMousePos.displacement.x, this.mousePos.x, this.lastMousePos.displacement.y, this.mousePos.y);
            this.dmScale = Math.min(lineEq(50, 0, 100, 0, mouseDistance), 50);   
            feDisplacementMapEl.scale.baseVal = this.dmScale;

            requestAnimationFrame(() => this.render());
        }
    }

    new Menu();
}

 

Thanks!

 

See the Pen NWPBprK by pkid (@pkid) on CodePen

Link to comment
Share on other sites

Hey pkid. 

 

As you pointed out, the issue is because the demo doesn't take into account the offset of the container. You have a couple of options:

  1. Move the SVG outside of the main container. That way it's not positioned based on the content above.
  2. Compensate for the content above in the JS. You can calculate the offset of the main container and subtract that from the y position.

Side note: That demo uses a pretty old version of GSAP. We highly recommend using GSAP 3! It has a smaller file size, a bunch of new features, and a sleeker API.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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