Jump to content
Search Community

Typewriter effect on mouseenter/mouseleave

aok test
Moderator Tag

Recommended Posts

I'm attempting to create a text (link) hover effect whereby if the mouse hovers over the link it would type the text out one by one but if the mouse hovers away it would return it to the full original text (like a reset).

 

I'm getting a bit lost with what approach to take. Should I simply set each letter opacity to 0 and show one after another? Should I set the innerHTML to empty then add in one letter at a time using the Text plugin?

 

I have a simple CodePen set up, which uses Alpine.js to speed up some of the "on" events but struggling to know where to go next with this. I've had a good look through the forums and demos but can't really find what I'm looking for. Any advice or examples would be appreciated.

See the Pen NWBaVOM?editors=1111 by richardcool (@richardcool) on CodePen

Link to comment
Share on other sites

17 minutes ago, mvaneijgen said:

is this what you're looking for? 

 

This looks good! So .reset() I guess doesn't exist, does it? So mouseleave is redundant? I guess this could work too... and it just always plays it out.

Link to comment
Share on other sites

Ah, my bad. I ment .revert() https://greensock.com/docs/v3/GSAP/Timeline/revert() this removes all properties the tween has used. You could also set .progress(1) to have it complete on mouse leave or .pause() it, it depends on what you're going for, but having .restart() on your mouse enter tween makes sure it always start from the beginning. 

Link to comment
Share on other sites

Hi,

 

What exactly is not working for you in your last codepen example? Based on the description you have provided it seems to be working as expected.

 

Using pause(0) is doing exactly what is supposed to do. Pauses the timeline's playhead at exactly 0 seconds. Maybe you could try just pausing the timeline without the time parameter:

function checkShouldStop() {
  if (shouldstop) tl.pause();
}

If that's not what you're after, please be as specific as possible about it in order to find the best possible approach.

 

Happy Tweening!

Link to comment
Share on other sites

Hi @Rodrigo apologies for not being clear.

 

In my CodePen, when you mouseenter it all works great. When you mouseleave it plays the current repeat iteration but then it applies the initial gsap.set which sets the characters to opacity: 0. I would've thought progress(0) or pause(0) method would set the timeline to before this?

Link to comment
Share on other sites

Hi,

 

So let's try to get this as clear as possible. You create a SplitText instance that splits the string into characters. You want to animate those characters on mouse over in an endless loop while the mouse is over the parent element. Once the mouse moves out of the parent element you want to complete the current repeat and then have the text visible. Is that the flow you're after?

Link to comment
Share on other sites

13 minutes ago, Rodrigo said:

Hi,

 

So let's try to get this as clear as possible. You create a SplitText instance that splits the string into characters. You want to animate those characters on mouse over in an endless loop while the mouse is over the parent element. Once the mouse moves out of the parent element you want to complete the current repeat and then have the text visible. Is that the flow you're after?

 

Yes. But I think if I set it to pause() instead of pause(0) then it would work so that's fine. See my updated CodePen 

See the Pen ZEjaMJe by richardcool (@richardcool) on CodePen

 – when you mouseleave it plays out the current repeat iteration then pauses at the end (which visually looks the same as before you start) so that's fine :)

  • Like 1
Link to comment
Share on other sites

Yep, indeed that was the idea, to pause the timeline at the end of the current iteration. Keep in mind that revert does a different thing that you might not want in this case:

https://greensock.com/docs/v3/GSAP/Timeline/revert()

 

Same thing with SplitText's revert:

https://greensock.com/docs/v3/Plugins/SplitText/revert()

 

That's why I proposed using pause() with no time parameter in this case, since that will allow you to restart the animation again.

 

Hopefully this clears things up. Let us know if you have more questions.

Happy Tweening!

Link to comment
Share on other sites

Thanks both @Rodrigo and @mvaneijgen – so appreciated.

 

One final thing. If I want to use this as a function across a site which passes in different elements/strings to be split and then animated on mouseenter/mouseleave what is the best way to do it?

 

On mouseenter event I could call a function that passes in the element and vice versa on mouseleave but I'm not sure how to use the same timeline instance for the mouseenter/mouseleave?

 

I thought the following would work but you can see the issues... 

See the Pen eYjePPx by richardcool (@richardcool) on CodePen

Link to comment
Share on other sites

I can write it as a forEach no problem BUT it would've been nice to have used Alpine's x:on-mouseenter and x:on-mouseleave's directives.

 

const linksWithHoverStates = document.querySelectorAll('.link-hover-state');

linksWithHoverStates.forEach(link => {

	const el = link.querySelector('span.link-hover-state-text');

	const split = new SplitText(el, { type: 'chars' });

	let shouldStop = false;

	const tl = gsap.timeline({
		repeat: -1, 
		paused: true, 
		onRepeat: () => {
			if (shouldStop) tl.pause();
		},
		repeatDelay: 0.5,
	})
	.set(split.chars, {
		opacity: 0
	})
	.to(split.chars, {
		duration: 0.01,
		opacity: 1,
		stagger: {
			each: 0.08
		}
	});

	link.addEventListener('mouseenter', (event) => {
		shouldStop = false;
		tl.restart();
	});

	link.addEventListener('mouseleave', (event) => {
		shouldStop = true;
	});

});

 

Link to comment
Share on other sites

Hi,

 

You can use an x-for loop in alpine and use the Alpine.data approach for re-usable data. I tried to do some stuff without any success. I know nothing about Alpine but even this didn't work on Codepen:

https://alpinejs.dev/directives/data#re-usable-data

 

I assume that it has to be related with something else but unfortunately we don't have the time resources to investigate and see how to make things work in a third party library. But this should be as simple as passing the data using an array, creating a loop (x-for in the case of alpine), creating the methods inside the x-data callback and passing those methods in the x-template wrapper, but unfortunately even that simple thing is not working 🤷‍♂️

 

But that should be the approach you should try in order to make this work. When I have more time I'll try to circle back to this and see if I can make it work with alpine.

 

In the mean time what I can see is that the reason for the weird behaviour you're seeing is because alpine is targeting only the final element but triggering the method on all of them. Also you're creating the SplitText instance on every mouse enter, no need for that, just create it once (NOT ON THE MOUSE ENTER EVENT) and use the mouse enter/leave events to play/pause each instance.

 

Happy Tweening!

  • Like 1
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...