Jump to content
Search Community

Search the Community

Showing results for 'overwrite'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • GreenSock Forums
    • GSAP
    • Banner Animation
    • Jobs & Freelance
  • Flash / ActionScript Archive
    • GSAP (Flash)
    • Loading (Flash)
    • TransformManager (Flash)

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Personal Website


Twitter


CodePen


Company Website


Location


Interests

Found 1,412 results

  1. Overwrite: none is not behaving how I imagined it would. In my codepen example I imagined that the second tween would be ignored because the first tween is already animating the element's "width". Instead it seems like the first tween is being overwritten despite overwrite being set to "none". Am I misunderstanding overwrite? Is there a way to accomplish what I want (where the second tween would be ignored because another tween has already 'claimed' the right to animated "width"?) http://codepen.io/anon/pen/BoJMvw Thanks for any help. -Ryan
  2. It looks like you're creating a ton of conflicting tweens that are fighting with each other. Set overwrite: true on your tween to have it immediately kill all other tweens of the same target. And I'm not sure why you're using two different ScrollTriggers for each element - why not just use one? https://stackblitz.com/edit/vue-fchh5m?file=src%2FApp.vue
  3. Can you explain what you mean? What are you wishing for that immediateRender doesn't provide? And if you just want to get something to render at a new playhead position, you can easily do that by setting the progress() or time(). Yes, that's very intentional and it's also easy to fix. We explain it here: In the old (v2 and earlier) version, the default overwrite mode was "auto". Now it is false because: It's faster (performance) because in the vast majority of cases people aren't creating conflicting tweens, so we can skip the processing involved in hunting down conflicts. It confused people in some cases because they didn't even know overwriting was a thing. The new behavior in v3 ensures that people opt-in to overwriting so that it never catches them off-guard. The fix: either set overwrite: "auto" (or true) in the new/overwriting tweens or you can just set the default mode for all animations to one of those like: gsap.defaults({overwrite: "auto"}); Does that clear things up?
  4. Hi everyone, Here is what I'm expecting to happen in the Codepen: 1. Click the "Bezier" button to animate the red box along a bezier path 2. While that is playing, click the "Highlight" button. The bezier tween should stop and the red box should animate up to the top left corner of the green box. 3. Click the "Bezier" button again. The red box should then animate back to it's original starting position and then start on the bezier path again. I thought setting overwrite:"all" would help accomplish this, but I can't get the "Highlight" button to work. If you click the "Highlight" button first then it does move the red box to the correct position, but it doesn't work if you click it second. If you click the "Play Vertical" and "Play Horizontal" buttons, then the red box does box in the appropriate direction. Even if you click them in different orders, so the overwrite appears to be working there? Any suggestions?
  5. Hm, it sounds like there may be some logic flaws in your code, but it's difficult to troubleshoot without a minimal demo. But I'll offer a few thoughts: It looks like you're reusing the same timeline instance over and over again and doing a clear() after it's done. That's not "wrong", but it's probably simpler to just create a new timeline each time (or if you're not sequencing things or need to control multiple as a whole, just skip the timeline altogether and use tweens). Remember that by default, when you add() something to the timeline, it gets added to the END of it. So let's say the user clicks multiple times quickly, that means your code is just sequencing the new ones after the current ones that haven't finished yet. See the problem? Or do you clear() it before running each time too? Again, it's tough to know by just looking at a small excerpt. You don't need to timeline.add(gsap.to(...)) - that's just a long way of using the convenience methods: // long timeline.add( gsap.to( ... )); // short timeline.to(...); Be careful about creating conflicting tweens where they're fighting to control the same property of the same object. You can set overwrite: true to have GSAP immediately kill all other tweens of those targets, or overwrite: "auto" to only kill the individual parts (properties) of the tweens that overlap. I'd rewrite your first block of code like this: // OLD let itemScrollTimeLine = gsap.timeline({ paused: true, onComplete: resetTimeline }); function resetTimeline() { console.log('Completed'); itemScrollTimeLine.clear(); } if (itemList.indexOf(elem.id) >= 0) { let elemPos = (window.innerHeight - document.getElementById(elem.id).offsetHeight) / 2; itemScrollTimeLine.add(gsap.to(window, { duration: 1.2, ease: "power1.inOut", scrollTo: { y: elem, offsetY: elemPos } })); } else { itemScrollTimeLine.add(gsap.to(window, { duration: 1.2, ease: "power1.inOut", scrollTo: { y: elem, offsetY: 100 } })); } itemScrollTimeLine.add(gsap.to(elem, { ease: "power3.inOut", duration: 0.8, '--line-color-top': '#a18248' }), '>'); // NEW let itemScrollTimeLine = gsap.timeline(); itemScrollTimeLine.to(window, { duration: 1.2, ease: "power1.inOut", overwrite: "auto", scrollTo: { y: elem, offsetY: itemList.indexOf(elem.id) >= 0 ? (window.innerHeight - document.getElementById(elem.id).offsetHeight) / 2 : 100 } }); itemScrollTimeLine.to(elem, { ease: "power3.inOut", overwrite: "auto", duration: 0.8, '--line-color-top': '#a18248' }); You really shouldn't need to getChildren() and remove() any of them. Ditch that altogether. I think that was more of a band-aid that was attempting to cover over the fundamental problem which had more to do with your reusing the same timeline and continuing to shove new tweens one-after-the-other or maybe overwriting (or lack thereof). If you're still having trouble, it'll greatly increase your chances of getting a solid answer if you can provide a minimal demo. Thanks for being a Club GreenSock member! ? Happy tweening!
  6. Yep, @akapowl is exactly right, and I'd follow his advice. If you really need to create the tweens dynamically each time (which can be beneficial sometimes like if you want them to pick up from the current state, but since you're using mostly .fromTo() tweens that doesn't matter), you could set overwrite: true or overwrite: "auto" on your tweens to tell them to find and kill any currently-animating ones of the same elements. https://codepen.io/GreenSock/pen/dydBMXE?editors=0010 Also, I'd strongly recommend always setting transforms via GSAP and use the shortcuts like scale, x, y, rotation, etc. Those are faster and they avoid the ambiguities that can come with using a "transform" value. See: Happy tweening!
  7. Hello, I wanted to overwrite the properties of same element on page animated in two different functions. e.g hover function: $(".showcase-item").hover(over, out); function over(){ var hoverAnimation = new TimelineMax(); hoverAnimation.to($(this).find(".showcase-background"), 0.5, {backgroundPosition: '50% 50%',ease: Power1.easeOut}); } function out(){ var hoverAnimation = new TimelineMax(); hoverAnimation.to($(this).find(".showcase-background"), 0.5, {backgroundPosition: '25% 50%',ease: Power1.easeOut}); } click function: $('.showcase-item').on("click", function(){ var showcaseOpen = new TimelineMax(); showcaseOpen.to($(this).parent(), 0.5, {width: '100%',position:'absolute',zIndex:9,ease: Power1.easeOut}) showcaseOpen.to($(this).find(".showcase-background"), 0.5, {scale:1.3,backgroundSize:'contain',backgroundPosition:'0% 50%',ease: Power1.easeOut,'-=0.2'); }); In above code, 'backgroundPosition' has two different values. I want backgroundPosition on hover to be overwritten by one on click.
  8. Hi @Roman S. is you're issue that your elements are not obeying the width you've set? That is because flexbox is trying to 'help', flexbox will automatically distribute the elements over the width you've given it. You can overwrite that using the flex-grow, flex-shrink and flex-basis property or the short hand flex: 0 0 "your width". You're right that this is a CSS issue and we like to focus these forums to just GSAP related questions. Still hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXOvgo?editors=0110
  9. Nice job, @Toso ? Minor tweaks: https://codepen.io/GreenSock/pen/KKxXjvW?editors=0010 I'd use backgroundColor rather than background, and I'd set the overwrite to either true or "auto" just in case the user rolls over/out quickly, you don't want to create conflicting animations.
  10. Hi guys! I come humbly in front of you with few drops of hope left, after 5 full days of switching between possible solutions to get a consistent ScrollTrigger behavior on a Gatsby site. Getting directly to you is my last resort, as every google and gsap forum link regarding ScrollTrigger and Gatsby is already visited. ? I cannot get a CodePen reproducing the exact issue so I'll try my best to describe it here. Shortly, the problem seems to be, as I suspect, that the ScrollTrigger does not refresh itself when Javascript pops into the browser on top of the SSR-ed html/css bundle. Here's what i did. I created several projects with different versions for dependencies, but i will stick to the simplest one with all dependencies up to date.It's a gatsby with material-ui plugin added, who's exact structure can be found here: https://github.com/mui-org/material-ui/tree/master/examples/gatsby There are no other plugins added, nor any other configs/plugins changed. I rendered the component that will contain the ScrollTrigger (AboutBlock) in the AboutPage page: about.js const AboutPage = () => { return ( <AboutBlock /> ) } export default AboutPage This is the component where i try to animate some elements on reveal when scrolled into view: aboutBlock.js import gsap from "gsap"; import ScrollTrigger from 'gsap/ScrollTrigger'; import animateReveal from "./gs_reveal"; export default function AboutBlock() { gsap.registerPlugin(ScrollTrigger) const revealRefs = useRef([]) revealRefs.current = [] useLayoutEffect(() => { let scrollTriggers = [] scrollTriggers = animateReveal(revealRefs.current) return () => { scrollTriggers.forEach(t => t.kill(true)) } }, []); const addToRevealRefs = el => { if (el && !revealRefs.current.includes(el)) { revealRefs.current.push(el); } }; return ( <Grid container> <Grid item width={{ xs: '100%', sm: '80%', md: '35%' }} pl={{ xs: 0, md: '2.5%' }} mt={{ xs: 60, sm: 0 }}> <Grid container direction="column" alignItems={{ xs: "flex-start", sm: "flex-end" }}> <Grid item mt={{ xs: 0, md: '10vh' }} id="acum"> <Typography variant="h5" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> NOW WE ARE IN </Typography> </Grid> <Grid item> <Typography variant="h6" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> LOCATION </Typography> </Grid> <Grid item mt="10vh" id="hi"> <Typography variant="h5" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> SAY HI </Typography> </Grid> <Grid item className='toughts'> <Typography variant="h6" textAlign={{ xs: "left", sm: "right" }} ref={addToRevealRefs} className='gs_reveal_fromRight'> TELL US YOUR THOUGHTS </Typography> </Grid> </Grid> </Grid> </Grid> } HTML is longer and crowded, I left a part to get the idea of the structure and styling approach (MUI's sx - emotion). And finally, this is the animateReveal function: gs_reveal.js import ScrollTrigger from 'gsap/ScrollTrigger'; import gsap from 'gsap'; export default function animateReveal(elements) { const triggers = [] elements.forEach(function (elem) { hide(elem) let tr = ScrollTrigger.create({ trigger: elem, id: elem.id, end: 'bottom top', markers: true, onEnter: function () { animateFrom(elem) }, onEnterBack: function () { animateFrom(elem, -1) }, onLeave: function () { hide(elem) } }); triggers.push(tr) }); return triggers; } function animateFrom(elem, direction) { direction = direction || 1; let x = 0, y = direction * 100; if (elem.classList.contains("gs_reveal_fromLeft")) { x = -100; y = 0; } else if (elem.classList.contains("gs_reveal_fromRight")) { x = 100; y = 0; } else if (elem.classList.contains("gs_reveal_fromBelow")) { y = -100 } elem.style.transform = "translate(" + x + "px, " + y + "px)"; elem.style.opacity = "0"; gsap.fromTo(elem, { x: x, y: y, autoAlpha: 0 }, { duration: 1.25, x: 0, y: 0, autoAlpha: 1, ease: "expo", overwrite: "auto", delay: elem.classList.contains("gs_delay") ? 0.3 : 0, }); } function hide(elem) { gsap.set(elem, { autoAlpha: 0 }); } The ScrollTrigger markers are misplaced when page loads, and might move (get more misplaced) on hard reloading page, depending on the current scroll position in the moment of reloading, even though the scroll position is not preserved on reload (always is scrolled on top). - The markers are placed on the correct position on resizing, as expected. I followed gsap official docs on react and react-advanced and tried: grabbing the html elements to animate on scroll inside animateReveal() by let elements = gsap.utils.toArray(".gs_reveal"); Assigning to each element a useRef() and use the .current value for each in animateReveal() grabbing html elements using gsap's selector utility gsap.utils.selector changing to simpler animation on scroll, like just a fade refreshing ScrollTrigger in different moments useLayoutEffect(() => { ScrollTrigger.refresh(true) // or ScrollTrigger.refresh() ... }, []); 6. Lifting ScrollTrigger logic to parent about.js page 7. Assigning scrollTrigger to a timeline triggered by the to-be-reveal element 8. Use useEffect() instead of useLayoutEffect() (recommended anyway for ScrollTrigger) 7. Other who-knows-what unsuccessful twists. I suspected a rehydration error, when the static generated code does not match the client side one. But the only JS that could cause a mismatch is the gsap related one, and it does not seem an SSR issue. I checked if the CSS and HTML elements are being properly SSR-ed, by preventing JS from running in the browser. All looking fine. This is both a SSR issue (gatsby build) and a development issue (no SSR). As i said on point 5, setting a ScrollTrigger.refresh() when component is mounted does not work, but delaying this with a 1-2 seconds in a setTimeout successfully solves the issue useLayoutEffect(() => { setTimeout(() => { ScrollTrigger.refresh(true) }, 2000); }, []); This is hard to be accepted as a solution, since i cannot rely on a fixed value to 'guess' when DOM is properly rendered in the eyes of the ScrollTrigger, not to mention the glitches that might occur. So, the question is 'WHY?', why animating with ScrollTrigger from within useLayoutEffect, which is not triggered on the server anyway and should mark the 'component is successfully mounted' moment, seems to not wait for the DOM being completely painted, even though nothing is generated dynamically! There are quite of threads on this forum regarding gatsby, and none seemed to have a clear cause-outcome-solution. Is this battle lost, should i move on? Do you have any suggestions? Thanks so much for your time reading this, it means so much to me!
  11. Yes you can! Like you do with CSS you can call all your elements at once and then use a stagger (see Stagger docs) to have them animate in one by one. Then when using a smart position parameter we can start the next animation right after the first one is done! Also you can target all transform properties directly with GSAP x, y, rotate, skew, scale ect and if you want to use percentage based values use xPercent and yPercent. I would also recommend keeping all he animation values to GSAP instead of setting something with in CSS that you then need to overwrite with GSAP, that is where .from() is really handy. I've sprinkled a lot of useful comments throughout your pen to explain certain parts, be sure to read through them! Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXmQqV?editors=0100 Oh and a side note! When working with ScrollTrigger I like to disable it, to really focus on just the animation I find it a lot easier. I've also added a repeat: -1, so be sure to remove those when you're going to enable ScrollTrigger again.
  12. Hello, i have tried the official codepen demo with the horizontalLoop: https://codepen.io/GreenSock/pen/gOvvJee Thanks for this awesome slider. But I run in some troubles with the dragging. I could fix some problems by myself but with 1 problem i have my troubles Scenario: - Open the page and drag much, so the slider its moving. - When it comes nearly to the end (but it has not stopped yet) please press the active button with the white boarders. - It now jumps a lot. Do you know why? Thanks a lot! Other bugs i could solve (but its ugly ? Scenario 1: - Open the page and drag just some pixels on the active button (Button number3) and release the mouse. - Then click a few times on the button 3. - Now it jumps some boxes. I tried to fix it in the "toIndex" function before line 150. It works better. vars.overwrite = true; if (index === curIndex) { return; } curIndex = newIndex; gsap.killTweensOf(proxy); return tl.tweenTo(time, vars); Scenario 2: - Drag a lot, so that the slider is moving. - While the slider is moving please press the "wrapper" (the grey lines above or below the boxes) - Now it jumps a loooot. I fixed this with adding a new var isNowDragging (true when the user drags) and change line 182. Seems to work now. if (!isNowDragging) {gsap.set(proxy, {x: startProgress / -ratio});} Thanks a lot for your help.
  13. Hello @F.D.C.H - welcome to the Forums. You could extend that helper function by a new variable - in the demo below I added startIndex = 0 up top where all the neccessary variables are being set up. In the draggables onPress you could set the startIndex = curIndex so at a later point (like on throwcomplete e.g.) you could check wether the value of the new curIndex is equal to the value of the startIndex. From outside the curIndex is accessible via tl.current() and I made the startIndex accessible via tl.dragStart() - but you could of course change the names to whatever you'd like. Of course the tl part here you would have to then exchange with whatever variable you are applying that horizontalLoop helper-function to. Then from outside you could do something like this. That's just an idea - I hope that will help loop.draggable.addEventListener("throwcomplete", log); function log() { console.log(loop.dragStart(), loop.current()) if( loop.dragStart() === loop.current() ) { console.log('Same Index') gsap.to(document.body, { backgroundColor: '#f00000', overwrite: 'auto' }) } else { console.log('New Index') gsap.to(document.body, { backgroundColor: '#111', overwrite: 'auto' }) } } https://codepen.io/akapowl/pen/KKQmPxB Edit: In this following pen the startIndex is also being set in the toIndex() function, so calling the check will also properly integrate with click on the buttons - and at this point the naming of tl.dragStart() doesn't seem appropriate anymore https://codepen.io/akapowl/pen/zYRwxBd
  14. Hello all, So in this codepen example I use Flip.from to get items into grid slots, and then on another flip to get them back in old parent, but also to transform each item to value I set with gsap.set. This works too, but on 3rd click, when I want to animate items again into grid, the gsap.set doesnt set xPercent value back to 0. I also tried overwrite: true but it didnt work. Is there something Im missing? Thanks
  15. Hi, I've been fiddling with your codepen example for a bit and this seems to do the trick: ScrollTrigger.create({ trigger: ".images", start: "center top", markers: true, onEnter: self => { let state = Flip.getState(images); images.forEach((image, i) => slots[i].appendChild(image)); gsap.set(images, {xPercent: 0, rotation: 0}); Flip.from(state, { duration: 6, overwrite: true, // <- HERE ease: "power1.inOut" }) } }) Since the first ScrollTrigger instance you're creating for the images has once: true, it doesn't really matter if the Flip animation overwrites those. In the tests that I've ran seems to work as expected: https://codepen.io/GreenSock/pen/ZEMeBKR Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  16. That's because you created conflicting animations - you've got your motionPath animation first in the timeline that controls the x/y position, and then you ALSO have another one that's affecting x to go in a completely different direction. So they're both fighting for control. If you do overwrite: "auto" (or true), all that does is basically KILL the overwritten part (so of course you won't see it affecting things after that point at all). You definitely should not be creating conflicting animations like that. The reason it looks different when scrolling forwards vs backwards is because the rendering order inverts in reverse. In other words, when moving the playhead forward, the LATER tween would render last whereas when moving the playhead backwards, the EARLIER tween would render last. That's exactly how it's supposed to work. Possible solutions: Don't overlap the animations. https://codepen.io/GreenSock/pen/dyqNQRR?editors=1010 Use a different (invisible) motionPath that has the shape you want. Basically copy the path you have now, but add that extra part at the top that's curved in the way you want your objects to travel. You can still leave the red stroked path as-is. Everything would look the same visually, but you'd just use one motionPath tween where the path actually has the shape you're going for. You technically could write a bunch of extra JavaScript to force things to render in a particular order no matter which direction the playhead travels, but honestly that seems quite hacky and unintuitive to me. It is doable, though. If you need help with that, we're available for paid custom consulting - just reach out directly to explore those options. I hope that helps!
  17. It looks like you just had your toggleActions wrong: // BAD toggleActions: "play none reverse none" // GOOD toggleActions: "play none none reverse" And this is not a valid start value: // invalid start: "-=200top top" I'm not sure if you meant "top top" or "200 top" or something else. But actually, if I were building this I'd approach it in a very different way: Put the color/backgroundColor into a data-color attribute on any element that I want to have this effect (a space-delimited value like "blue white") Grab all the elements that have that data-color attribute, loop through them and create a ScrollTrigger for each. When it activates, create a new tween that animates to its colors. Here's a demo with my strategy implemented: https://codepen.io/GreenSock/pen/OJoROgY?editors=0010 Benefits: You can easily add as many sections as you want - just slap a data-color value on it in the markup and BOOM, it works. It works more smoothly if you scroll very quickly. With your previous strategy, you had one animation for each section, and you were calling play()/reverse() on them when necessary...but they were controlling the same properties of the same object. Imagine a scenario where the user scrolls quickly, so one animation starts and is midway through when the other animation gets triggered. Now you've got two animations fighting for control of the same properties. Plus you may see a jump because let's just say (to make it simpler) we're animating a number from 0 to 100 in the first one, and 100 to 200 in the second animation. If the first animation is at 50 when the second one starts playing, you'd see it jump from 50 to 100 instantly (and go to 200). With my strategy above, a new tween gets created each time so that it's just taking the value from whatever it currently is to the new value. So everything is perfectly smooth every time. No fighting for control (it has overwrite: "auto"), no overlapping. I hope that helps.
  18. You're creating a tween at the end for that, so you could just use an onComplete on that tween to know when it's done. Beware, though - you are creating a whole new tween EVERY time there's any movement and you didn't set overwrite: true (or "auto") so you're technically creating a bunch of conflicts. I'd recommend setting overwrite: true or "auto". I'd personally recommend using the new gsap.quickTo() method instead for maximum performance.
  19. Heya! Ok so there's a couple of things I can recommend here. First up - overwrite modes. You're using true which is killing the conflicting tweens. You don't want that. You only want to overwrite the conflicting parts true: Any existing tweens that are animating the same target (regardless of which properties are being animated) will be killed immediately. "auto": Only the conflicting parts of an existing tween will be killed. Next, no need for an open and close timeline. We can create one timeline and then manage it with control methods. like tl.play(0) and tl.reverse()- then the timeline is interruptible, if you click open and close really quickly it'll just change the direction the timeline is animating. Here's an adjusted demo. https://codepen.io/GreenSock/pen/ZErEZEK?editors=0010
  20. I'm still pretty fuzzy on what you're asking here, but here are a few comments in case they're helpful: When you set overwrite: true on a tween, that overwriting logic only runs ONCE, immediately when you create the tween. It basically says "find all other tweens of the same target and kill them right now." With overwrite: "auto", it runs once the first time the animation renders and it finds only other active tweens of the same target(s) and kills only the individual conflicting properties. It would be very very bad for performance if it tried to run the overwrite logic every single time that animation rendered/played. We obsess about performance around here because animation is the most performance-sensitive part of UX. It sounds like maybe you're expecting that every time you .play() one timeline, it will kill any other timelines but that is NOT true. When something is overwritten, it's dead. Gone. It doesn't come back later. The first time a tween renders, it records the start/end values so that it can very quickly interpolate between them. Again, that happens ONCE. It sounds like you might be expecting that to happen every time you play() a timeline. So, for example, if box.x is 0 and then you have a .to(box, {x: 100}) in a timeline, the first time it renders it will record "okay, we're going from 0 to 100. Lock that in". So now every time that timeline plays again, it ALWAYS goes from 0 to 100. However, let's say you set box.x to 200 somewhere else in your code and then you .play() this timeline again - you shouldn't expect it to animate from 200 to 100 (instead of 0 to 100) because it already locked in the starting value of 100. You can .invalidate() a tween/timeline to force it to flush any pre-recorded values and then it'll re-record them the next time it renders. If you have multiple timelines that affect the same properties of the same targets, you can easily prevent them from conflicting by calling .pause() on the ones that shouldn't be playing, and .play() the one that should. Again, if you want them to flush any recorded starting values, just call .invalidate(). I cannot imagine why it would take days to set up a minimal demo - all we need is the most basic possible illustration. Hopefully that wouldn't take more than 10 minutes. Maybe 2 buttons and 2 timelines with a couple of tweens in each that affect a single <div> or something(?) We're eager to help and I'm sure that minimal demo will go a long way to allowing us to get you the answer you're looking for.
  21. You definitely shouldn't be using WebKitCSSMatrix like that - it would be much cleaner (and more compatible) to use a simple gsap.getProperty(".ticker-wrapper", "x") but you don't even need to do that. Here's a different approach that leverages a simple xPercent animation: https://codepen.io/GreenSock/pen/rNwaLvw?editors=0010 $(document).ready( function(){ $('ul li').wrapAll('<span class="ticker-items">'); var tickerWidth = $('ul').width(); var spanWidth = $('ul span').width(); $('ul span').clone().appendTo('ul'); $('ul span').wrapAll('<span class="ticker-wrapper">'); var speed = 50, tl = gsap.timeline(); tl.fromTo(".ticker-wrapper", { // intro (from far right edge) xPercent: tickerWidth / spanWidth / 2 * 100 }, { xPercent: 0, duration: tickerWidth / speed, ease: "none" }).to(".ticker-wrapper", { // loop xPercent: -50, ease: "none", duration: spanWidth / speed, repeat: -1 }); $('ul').on('mouseenter', () => gsap.to(tl, {timeScale: 0, overwrite: true})); $('ul').on('mouseleave', () => gsap.to(tl, {timeScale: 1, overwrite: true})); }); Notice that in the mouseenter/mouseleave I'm actually animating the timeScale of the timeline so that it gradually slows down or speeds up instead of suddenly stopping/starting. I just think that feels nicer, but you're welcome to do a simple tl.pause() and tl.play() if you prefer. However, I think the problem you mentioned in your previous post has to do with the fact that only one clone is done in that code because it assumes your content fills the container. You could add a loop in there to clone it multiple times but I was inspired to create a gsap.effect.ticker that should help with this: https://codepen.io/GreenSock/pen/rNwaMPo?editors=0010 gsap.registerEffect({ name: "ticker", effect(targets, config) { let master = gsap.timeline(); buildTickers(targets, config); function clone(el) { let clone = el.cloneNode(true); el.parentNode.insertBefore(clone, el); clone.style.position = "absolute"; return clone; } function nestChildren(el, className) { let div = document.createElement("div"); while (el.firstChild) { div.appendChild(el.firstChild); } el.appendChild(div); className && div.setAttribute("class", className); div.style.display = "inline-block"; div.style.boxSizing = "border-box"; return div; } function buildTickers(targets, config, isResize) { if (isResize) { // on window resizes, we should delete the old clones and reset the widths targets.clones.forEach(el => el && el.parentNode && el.parentNode.removeChild(el)); gsap.set(targets.chunks, {x: 0}); } else { targets.clones = []; targets.chunks = []; } master.clear(); let clones = targets.clones, chunks = targets.chunks; targets.forEach((el, index) => { let chunk = chunks[index] || (chunks[index] = nestChildren(el, config.className)), chunkWidth = chunk.offsetWidth + (config.padding || 0), cloneCount = Math.ceil(el.offsetWidth / chunkWidth), chunkBounds = chunk.getBoundingClientRect(), elBounds = el.getBoundingClientRect(), right = (el.dataset.direction || config.direction) === "right", tl = gsap.timeline(), speed = parseFloat(el.dataset.speed) || config.speed || 100, i, offsetX, offsetY, bounds, cloneChunk, all; el.style.overflow = "hidden"; gsap.getProperty(el, "position") !== "absolute" && (el.style.position = "relative"); // avoid scrollbars for (i = 0; i < cloneCount; i++) { cloneChunk = clones[i] = clone(chunk); if (!i) { bounds = cloneChunk.getBoundingClientRect(); offsetX = bounds.left - chunkBounds.left; offsetY = bounds.top - chunkBounds.top; } gsap.set(cloneChunk, {x: offsetX + (right ? -chunkWidth : chunkWidth) * (i + 1), y: offsetY}); } all = clones.slice(0); all.unshift(chunk); tl.fromTo(all, { x: right ? "-=" + (chunkBounds.right - elBounds.left) : "+=" + (elBounds.right - chunkBounds.left) }, { x: (right ? "+=" : "-=") + elBounds.width, ease: "none", duration: elBounds.width / speed, overwrite: "auto" }).to(all, { x: (right ? "+=" : "-=") + chunkWidth, ease: "none", duration: chunkWidth / speed, repeat: -1 }); master.add(tl, 0); }); // rerun on window resizes, otherwise there could be gaps if the user makes the window bigger. isResize || window.addEventListener("resize", () => buildTickers(targets, config, true)); } return master; } }); Once that effect is registered, all you have to do is: let tl = gsap.effects.ticker(".ticker", { speed: 100, className: "ticker-content", //direction: "right" }); So you can tweak the speed, direction, and the class name that's added to the wrapper <div> elements around the chunks. It dynamically figures out how many clones to make. It even handles resizes. You can even add data-speed or data-direction attributes to the elements instead of passing that in through the config object. I hope that helps!
  22. Hi! Thank you bringing us GSAP and providing such a great support. We are struggling a little with making the overwrite options work the way we understood in the documentation they should work. We are designers and not professional programmers. These are the lines of code we're using to test it: TweenLite.to( basePath.position, 1, { y: "-=250", delay: 0, overwrite: 0, onOverwrite: reTween } ); TweenLite.to( basePath.position, 2, { y: "+=250", delay: 0.5, overwrite: 0, onOverwrite: reTween } ); We don't seem to be able to prevent the second tween from overwriting the first one half way of it. What are we missing or doing wrong? Thank you!
  23. Welcome to the forums @AFoeee You really don't have to call then, and using overwrite: "auto" only kills the property animations that are conflicting. Animations are set to resolve on complete, so it wouldn't make sense to resolve tween1 in the code below when the new animation starts as the x animation is still going to run its natural course. let tween1 = gsap.to(".box", { x: 100, y: 100 }); setTimeout(() => { gsap.to(".box", { y: 200, overwrite: "auto" }) }, 100) Maybe we can add in something to resolve if the entire animation is killed, but for now you would have to force it to complete, maybe like this. GSAP .then() interruption test (codepen.io)
  24. I think having overwrite set to false is really only helpful to people who create conflicting animations in banner-like animations. When doing interactive animations, having overwrite set to false can really mess people up because most people are not familiar with the different overwrite behaviors. I've been using gsap since 2014, and the new overwrite behavior still messes me up. I looked at this question last night, and it didn't occur to me that it might be an overwrite issue. I understand the reasoning for having overwrite set to false, but I think it does more harm than good.
  25. Hey Yandex. Some notes: I highly recommend overwrite: "auto" instead of overwrite: true because it will only kill off the conflicting tweens. You probably want to set defaults: {overwrite: "auto"} instead so it's passed to each tween. Why are you using keyframes here? Using regular tweens fixes the issue because defaults on timelines won't get passed to keyframes. They don't get passed to keyframes because keyframes essentially create a sub-timeline and defaults don't apply to those. If you want defaults on keyframes, apply it to the tween itself. You could technically pass in a defaults option that sets the defaults for each tween. Kinda meta but it works: defaults: { defaults: { overwrite: "auto" } } Another alternative is to use the global defaults for gsap: gsap.defaults({overwrite: "auto"}); I'd just use regular tweens: https://codepen.io/GreenSock/pen/WNreEaa?editors=0010
×
×
  • Create New...