Jump to content
Search Community

Animating different Elements on hover

hendrikeng test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hey there, 

happy new year first of all :-)

 

I am a bit confused with an animation i tried to achieve...

i basically want to have each image separately  animated and not all of them together...i tried to loop over all elements but  its still animating all images together...would i need a timeline or is the approach completely wrong?

 

const who = {
  trigger: [...document.querySelectorAll(".slide")],
  image: [...document.querySelectorAll(".slide img")],

  init: () => {
    who.trigger.forEach(element => {
      element.addEventListener("mouseover", who.animateOnMouseEnter);
      element.addEventListener("mouseout", who.animateOnMouseOut);
    });
  },

  animateOnMouseEnter: () => {
    console.log("animateOnMouseEnter");
    who.image.forEach(element => {
      TweenMax.to(element, 0.25, {
        y: 35,
        ease: Power1.easeOut,
        repeat: 0
      });
    });
  },

  animateOnMouseOut: () => {
    console.log(" animateOnMouseOut");
    who.image.forEach(element => {
      TweenMax.to(element, 0.75, {
        y: 0,
        ease: Bounce.easeOut,
        repeat: 0
      });
    });
  },

  debug: () => {
    //
  },

  destroy() {
    //
  }
};

who.init();


 

 

See the Pen aEKPmM?editors=1111 by HendrikEng (@HendrikEng) on CodePen

Link to comment
Share on other sites

Thanks a lot @mikel that really helped!

 

If anyone needs the jQuery free version of mikels pen : 

TweenLite.set(".page", { autoAlpha: 1, xPercent: -100 });

const page = document.querySelectorAll(".page");
const button = document.querySelectorAll(".button");

button.forEach.call(button, function(el) {
  el.addEventListener("mouseover", function(e) {
    let thisPage = this.getAttribute("id");

    TweenMax.to(page, 0.2, {
      xPercent: -100,
      ease: Sine.easeInOut,
      onComplete: newImage
    });

    function newImage() {
      TweenMax.to(thisPage, 0.8, {
        delay: 0.4,
        xPercent: 0,
        ease: Sine.easeInOut
      });
    }
  });
});

button.forEach.call(button, function(el) {
  el.addEventListener("mouseout", function(e) {
    let thisPage = this.getAttribute("id");
    console.log(thisPage);
    TweenMax.to(page, 0.4, { xPercent: -100, ease: Power2.easeIn });
  });
});

 

 

thanks again :-)

  • Like 2
Link to comment
Share on other sites

I tried to extend my code but run into a new issue.

 

i am trying to understand how i would pass an argument to a function inside a forEach.call. I basically converted my code into an object literal and split up the functions to be more dry when i would later add more animations.

The problem is, that it logs the element on load but not anymore after that, i guess its because the variable doesn't exist after the first log anymore. how would i make it work, or is the approach completely wrong and nonsense? 

 

thanks for all the help.

 

const who = {
  trigger: [...document.getElementsByClassName('slide')],

  init: () => {
    console.log('init');
    who.trigger.forEach.call(who.trigger, (el) => {
      el.addEventListener('mouseover', who.animateOver(el), false);
    });
    who.trigger.forEach.call(who.trigger, (el) => {
      el.addEventListener('mouseout', who.animateOut(el), false);
    });
  },

  animateOver: (el) => {

    // animate image
    const image = el.getElementsByClassName("img")[0];

    TweenMax.to(image, 0.25, {
      yPercent: 35,
      ease: Power1.easeOut,
    });
    
      // animate text
    const text = el.getElementsByClassName("text")[0];

    TweenMax.to(text, 0.25, {
      yPercent: 35,
      ease: Power1.easeOut,
    });
  },

  animateOut: (el) => {
    
    // animate image

    const image = el.getElementsByClassName('img')[0];
    TweenMax.to(image, 0.75, {
      yPercent: 0,
      ease: Bounce.easeOut,
    });
    
    // animate something different
     const text = el.getElementsByClassName('text')[0];
    TweenMax.to(text, 0.75, {
      yPercent: 0,
      ease: Bounce.easeOut,
    });
    
  },

  debug: () => {
    console.log('debug');
  },

  destroy() {
    console.log('destroy');
  },
};

who.init();

 

See the Pen XVBpPV?editors=0011 by HendrikEng (@HendrikEng) on CodePen

 

 

 

It does work if i don't pass an argument but the problem here is that it just triggers the events target and will result in stuttering and not being able to choose the actual trigger (i want to have both triggered when hovering the image and not on hovering text or image) if that makes sense this is the example: 

 

https://codepen.io/HendrikEng/pen/ypqMNP?editors=1111

 

const who = {
  trigger: [...document.getElementsByClassName('slide')],

  init: () => {
    console.log('init');
    who.trigger.forEach.call(who.trigger, (el) => {
      el.addEventListener('mouseover', who.animateOver, false);
    });
    who.trigger.forEach.call(who.trigger, (el) => {
      el.addEventListener('mouseout', who.animateOut, false);
    });
  },

  animateOver: (el) => {
    // animate image
    const image = el.target;
    TweenMax.to(image, 0.25, {
      yPercent: 35,
      ease: Power1.easeOut,
    });
    // animate text
    /* const text = el.target;
    TweenMax.to(text, 0.25, {
      css: {
            opacity: '0',
          },
      ease: Power1.easeOut,
    });
    */
  },

  animateOut: (el) => {
    // animate image
    const image = el.target;
    TweenMax.to(image, 0.75, {
      yPercent: 0,
      ease: Bounce.easeOut,
    });
    // animate Text
    /*
    const text = el.target;
    TweenMax.to(text, 0.75, {
      css: {
            opacity: '0',
          },
    });
    */
  },

  debug: () => {
    console.log('debug');
  },

  destroy() {
    console.log('destroy');
  },
};

onload = () => who.init();

 

Link to comment
Share on other sites

Thanks a lot @mikel, i guess i might have overcomplicated things :-) , i managed to get it working. 

 

I basically wanted to avoid doubling the code for the touch events, anyways it works so far.

 

 

Thanks a again for the help 

 

const who = {
  trigger: [...document.getElementsByClassName('slide')],

  init: () => {
    console.log('init');
    who.trigger.forEach.call(who.trigger, (el) => {
       el.addEventListener('mouseover', who.animateOver, false);
      el.addEventListener('touchstart', who.animateOver, false);
    });
    who.trigger.forEach.call(who.trigger, (el) => {
      el.addEventListener('mouseout', who.animateOut, false);
      el.addEventListener('touchend', who.animateOut, false);
    });
  },

  animateOver() {
    const image = this.getElementsByClassName('image');
    const heading = this.getElementsByClassName('text1');
    const subheading = this.getElementsByClassName('text2');

    // animate image
    TweenMax.to(image, 0.25, {
      yPercent: 35,
      ease: Power1.easeOut,
    });
    // animate heading
    TweenMax.to(heading, 0.75, {
      yPercent: -180,
      ease: Power1.easeOut,
    });
    // animate subheading
    TweenMax.to(subheading, 0.75, {
      yPercent: -90,
      ease: Power1.easeOut,
    });
  },
  
 animateOut() {
    const image = this.getElementsByClassName('image');
    const heading = this.getElementsByClassName('text1');
    const subheading = this.getElementsByClassName('text2');
    // animate image
    TweenMax.to(image, 0.75, {
      yPercent: 0,
      ease: Bounce.easeOut,
    });
    // animate heading
    TweenMax.to(heading, 0.75, {
      yPercent: 0,
      ease: Bounce.easeOut,
    });
    // animate subheading
    TweenMax.to(subheading, 0.75, {
      yPercent: 0,
      ease: Bounce.easeOut,
    });
  },
};

who.init();

See the Pen XVBpPV?editors=0011 by HendrikEng (@HendrikEng) on CodePen

 

  • Like 2
Link to comment
Share on other sites

  • 2 years later...

Hi,

My use case is simpler in that I want a row of Bootstrap cards to jump out of the page on hovering over each.

Just for future people really: this is using Gatsby, Bootstrap and GSAP andseems to work well enough: I ended up on this thread since I couldn't get mouseover events to fire on the right item (sometimes it would fire but then target descendents if the mouse was moving fast) when using onMouseOver/ Out/  Enter/ Leave.

 

Suggestions or improvements welcome.

 

import React, { Component } from 'react';
import { 
    Row
from "react-bootstrap"
 
import { gsapCSSPlugin } from 'gsap/all';
//need this to avoid tree shake of CSSPlugin
gsap.registerPlugin(CSSPlugin)
 
class Amination extends Component {
  constructor(props) {
    //create the empty references as normal
    super(props); 
    this.children = props.children.map ((item=>
      <div className='col-xl-3 d-flex align-items-stretch'>{item}</div>
    );
  }
 
  animationIn(el){
    el.addEventListener('mouseover'function(e){
      const myTween = new gsap.timeline({paused: true, repeat:0});
      myTween
      .to (el, {
        scale: 1.1,
      })
      .play()
    })
  }
 
  animationOut(el){
    el.addEventListener('mouseout'function(e){
      const myTween = new gsap.timeline({paused: true, repeat:0});
      myTween
      .to (el, {
        scale:1,
 
      })
      .play()
    })
  }
  
  componentDidMount(){
    
    const element = document.querySelectorAll('.card');
    element.forEach(this.animationOut);
    element.forEach(this.animationIn);
 }
 
  //the render
  render() {
    return (
      <>
        <Row>
          {this.children}
        </Row>
      </>
    );
  }
}
 
export default Animation;
Link to comment
Share on other sites

30 minutes ago, Tony TAB said:

Suggestions or improvements welcome.

 

There is no need for this. 

import { gsap, CSSPlugin } from 'gsap/all';
//need this to avoid tree shake of CSSPlugin
gsap.registerPlugin(CSSPlugin)

 

Just follow the installation docs.

https://greensock.com/docs/v3/Installation

 

All you need to do is import gsap.

import { gsap } from "gsap";

 

For hover, you should use mouseenter and mouseleave events.

 

Do not use new when creating a timeline. And there is no need to pause a timeline and play it. 

// BAD
const myTween = new gsap.timeline({paused: true, repeat:0});
myTween
  .to (el, {
  scale: 1.1,
})
  .play()
})

// GOOD
gsap.timeline()
  .to(el, { scale: 1.1 })

 

You're only animating one thing, so a tween is more appropiate.

gsap.to(el, { scale: 1.1 });

 

You're using React. You should be using what React DOM provides, not vanilla JS.

 

See the Pen 726d292638779b216881263f4d8be4a1 by osublake (@osublake) on CodePen

 

 

  • Like 2
Link to comment
Share on other sites

2 hours ago, Tony TAB said:

In the past, if I haven't done that, Gatsby build often fails even though development works.  See this thread

 

That's because you were importing from "gsap/all", and you weren't importing gsap. You also need to make sure you have the latest version.

 

 

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...